/**
\file   ucmidi.h
\brief  uC-MIDI Library (MIDI for Microcontrollers) Definitions.

Copyright (c) 2013 Gene Kozin <gkozin(at)gmail.com>

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#ifndef __UCMIDI_H__
#define __UCMIDI_H__

/* Unsigned 8-bit value type */
#ifndef BYTE
# define BYTE   unsigned char
#endif

/* Comment this out if you don't require MIDI parser */
#define UCMIDI_HAS_MIDI_PARSER

/* Comment this out if you don't require MIDI send APIs */
#define UCMIDI_HAS_MIDI_SEND

/* Maximum supported MIDI SysEx message size */
#define UCMIDI_MAX_SYSEX_SIZE   32

/* Library version */
#define UCMIDI_VERSION_MAJOR    1
#define UCMIDI_VERSION_MINOR    1

/* MIDI commands */
#define MIDI_NOTE_OFF           0x80 /* Note Off */
#define MIDI_NOTE_ON            0x90 /* Note On */
#define MIDI_KEY_PRESSURE       0xA0 /* Polyphonic Key Pressure */
#define MIDI_CC                 0xB0 /* Controller Change */
#define MIDI_PROGRAM            0xC0 /* Program Change */
#define MIDI_CHAN_PRESSURE      0xD0 /* Channel Pressure */
#define MIDI_PITCH_BEND         0xE0 /* Pitch Bend */
#define MIDI_SYSEX              0xF0 /* start of SysEx message */
#define MIDI_TIME_CODE          0xF1 /* Time Code */
#define MIDI_SONG_POSITION      0xF2 /* Song Position Pointer */
#define MIDI_SONG_SELECT        0xF3 /* Song Select */
#define MIDI_TUNE_REQUEST       0xF6 /* Tune Request */
#define MIDI_EOX                0xF7 /* end of SysEx message */
#define MIDI_CLOCK              0xF8 /* Timing Clock */
#define MIDI_START              0xFA /* Start */
#define MIDI_CONTINUE           0xFB /* Continue */
#define MIDI_STOP               0xFC /* Stop */
#define MIDI_ACTIVE_SENSE       0xFE /* Acrive Sense */
#define MIDI_SYSTEM_RESET       0xFF /* System Reset */

/* MIDI command flag */
#define MIDI_CMD_FLAG           0x80

/* MIDI command mask */
#define MIDI_CMD_MASK           0xF0

/* MIDI channel mask */
#define MIDI_CHAN_MASK          0x0F

/* MIDI data mask */
#define MIDI_DATA_MASK          0x7F

/* Macros for parsing MIDI status byte */
#define MIDI_GET_CMD(b)         ((b) & MIDI_CMD_MASK)
#define MIDI_GET_CHAN(b)        ((b) & MIDI_CHAN_MASK)

/* Macro to combine two MIDI data bytes into an integer */
#define MIDI_MAKE_INT(lsb, msb) ((lsb) + ((msb) << 7))

/* Returns MIDI Least Significant Byte (lower 7 bits of integer) */
#define MIDI_GET_LSB(word)      ((word) & 0x7F)

/* Returns MIDI Most Significant Byte (upper 7 bits of integer) */
#define MIDI_GET_MSB(word)      (((word) >> 7) & 0x7F)

#ifdef __cplusplus
extern "C" {
#endif

/**
\brief  Returs uC-MIDI library version.
**/
int ucmidi_version(void);

#ifdef UCMIDI_HAS_MIDI_PARSER
/***************************************************************************
MIDI Parser Definitions
***************************************************************************/

/* MIDI Dispatch Table */
typedef struct {
    void (*note_on)(BYTE chan, BYTE note, BYTE velocity);
    void (*note_off)(BYTE chan, BYTE note, BYTE velocity);
    void (*key_pressure)(BYTE chan, BYTE note, BYTE pressure);
    void (*control_change)(BYTE chan, BYTE number, BYTE value);
    void (*program_change)(BYTE chan, BYTE number);
    void (*chan_pressure)(BYTE chan, BYTE pressure);
    void (*pitch_bend)(BYTE chan, int value);
    void (*sysex)(BYTE const* data, int len);
    void (*time_code)(BYTE value);
    void (*song_position)(int position);
    void (*song_select)(BYTE number);
    void (*tune_request)(void);
    void (*clock)(void);
    void (*start)(void);
    void (*cont)(void);
    void (*stop)(void);
    void (*active_sense)(void);
    void (*reset)(void);
} midi_callback_t;

/**
\brief  Initializes uC-MIDI parser.
**/
void ucmidi_init(midi_callback_t const* cb);

/**
\brief  Parses MIDI input data.
**/
void midi_parser(BYTE c);

#endif /* UCMIDI_HAS_MIDI_PARSER */

#ifdef UCMIDI_HAS_MIDI_SEND
/***************************************************************************
MIDI Send APIs
***************************************************************************/

void send_note_on(BYTE chan, BYTE note, BYTE velocity);
void send_note_off(BYTE chan, BYTE note, BYTE velocity);
void send_key_pressure(BYTE chan, BYTE note, BYTE pressure);
void send_control_change(BYTE chan, BYTE number, BYTE value);
void send_program_change(BYTE chan, BYTE number);
void send_chan_pressure(BYTE chan, BYTE pressure);
void send_pitch_bend(BYTE chan, int value);
void send_sysex(BYTE const* data, int len);
void send_time_code(BYTE value);
void send_song_position(int position);
void send_song_select(BYTE number);
void send_tune_request(void);
void send_clock(void);
void send_start(void);
void send_continue(void);
void send_stop(void);
void send_active_sense(void);
void send_reset(void);

/**
\brief  Returns result of the last MIDI send operation.
**/
int midi_errno(void);

/**
\brief  Sends MIDI message to the MIDI Out port.
\note   This function must be provided by the application or defined as a
        macro.
**/
#ifndef midi_send
extern int midi_send(BYTE const* msg, int len);
#endif

#endif /* UCMIDI_HAS_MIDI_SEND */

#ifdef __cplusplus
}
#endif

#endif /* __UCMIDI_H__ */
